/*
 * main.cpp
 *
 *  Created on: Apr 4, 2012
 *      Author: ajeffery
 */
#include "Tester.h"
#include <string.h>
#include <stdlib.h>
#include <stdio.h>
#include <unistd.h>

#include "../Elevator.h"
#include "../Supervisor.h"
#include "../defs.h"
#include "../Comm_Manager.h"
#include "../Double_Buffer.h"
#include "../FloorRun_Manager.h"

#include <netinet/in.h>
#include <netinet/tcp.h>
#include <sys/socket.h>
#include <arpa/inet.h>

#include <sys/mman.h>
#include <rtdk.h>
#include <native/task.h>

RT_TASK test_task1;
RT_TASK test_task2;

//Global
Elevator *this_lift;
int ecTestsock =0;

int pratice_passed(){
	return 1;
}
int pratice_failed(){
	return -1;
}

int testElevator_getters () {
	if ( !(this_lift->getCar_num() == 0) )
		return -1;
	if (!(this_lift->getCur_floor() == 0))
		return -1;
	if (! (this_lift->getDest_floor() == (this_lift->getCur_floor()+1)))
		return -1;
	if (  !( this_lift->getDirection() == UP))
		return -1;
	if ( !(this_lift->getStatus() == SPOOLING))
		return -1;

	return 1;		//PASSED
}

int testElevator_setters (){

	this_lift->setCur_floor(MAX_FLOORS -1);
	this_lift->setDest_floor(MAX_FLOORS -1);
	this_lift->setDirection(DOWN);
	this_lift->setStatus(MOVING);

	if (!(this_lift->getCur_floor() == MAX_FLOORS -1))
		return -1;
	if (! (this_lift->getDest_floor() == MAX_FLOORS -1))
		return -1;
	if ( ! ( this_lift->getDirection() == DOWN))
		return -1;
	if (! (this_lift->getStatus() == MOVING))
		return -1;

	return 1;		//PASSED
}

int testElevator_arrayInit(){
	//reset Elevator Classes for other tests
	delete (this_lift);
	this_lift=new Elevator(0);

	int8_t test_call_array[MAX_FLOORS];
	int8_t test_floor_array[MAX_FLOORS];
	memset((void*)test_call_array, 0, MAX_FLOORS);
	memset((void*)test_floor_array, 0, MAX_FLOORS);

	this_lift->getCur_hall_calls(test_call_array);
	this_lift->getInternal_calls(test_floor_array);

	for (int i=0; i <MAX_FLOORS; i++){
		if (test_call_array[i] != 0 && (i != this_lift->getDest_floor())){
		//	printf("Call%d::%d", i, test_call_array[i]);
			return -1;
		}
		if ((test_floor_array[i] != 0) && (i != this_lift->getDest_floor())){
		//	printf("Flor%d::%d", i, test_floor_array[i]);
			return -1;
		}
	}

	if(test_floor_array[this_lift->getDest_floor()] != 1)
		return -1;

	return 1; 		//PASSED
}

int testElevator_arrayClear(){
	//reset Elevator Classes for other tests
	delete (this_lift);
	this_lift=new Elevator(0);

	int8_t test_call_array[MAX_FLOORS];
	int8_t test_floor_array[MAX_FLOORS];
	memset((void*)test_call_array, 0, MAX_FLOORS);
	memset((void*)test_floor_array, 0, MAX_FLOORS);

	int8_t blank_array[MAX_FLOORS];
	int8_t set_array[MAX_FLOORS];
	memset((void*)blank_array, 0, MAX_FLOORS);
	memset((void*)set_array, 1, MAX_FLOORS);

	//Set all bits to true
	this_lift->add_hall_calls(set_array);

	for (int i =0 ; i<MAX_FLOORS; i++)
		this_lift->addInternal_call(i);

	this_lift->getCur_hall_calls(test_call_array);
	this_lift->getInternal_calls(test_floor_array);

	for (int i=0; i <MAX_FLOORS; i++){
		if (test_call_array[i] != 1)
			return -1;
		if (test_floor_array[i] != 1 )
			return -1;
	}

	//clear all bits
	this_lift->cancel_hall_calls(set_array);

	for (int i =0 ; i<MAX_FLOORS; i++)
		this_lift->remove_internal_call(i);

	this_lift->getCur_hall_calls(test_call_array);
	this_lift->getInternal_calls(test_floor_array);

	for (int i=0; i <MAX_FLOORS; i++){
		if (test_call_array[i] != 0)
			return -1;
		if (test_floor_array[i] != 0 )
			return -1;
	}

	return 1;		//PASSED

}

int testSupervisor_create(){
	Supervisor *testobject;
	testobject= new Supervisor();
	if (!testobject)
		return -1;

	delete(testobject);

	return 1; 		//PASSED
}

void testComm_connect_t1(void* arg){
	int * ret;
	ret = (int*) arg;
	Comm_Manager *testComm;
	testComm = new Comm_Manager(new Double_Buffer());
	delete(testComm);
}

void testComm_connect_t2(void* arg){
	int * ret;
	struct sockaddr_in serv_addr;

	ret = (int*) arg;
	if (ecTestsock ==0){
			ecTestsock = socket(AF_INET, SOCK_STREAM, 0);
		if (ecTestsock < 0) {
			*ret = -1;
		}
		serv_addr.sin_family = AF_INET;
		serv_addr.sin_addr.s_addr = htonl(INADDR_ANY);
		serv_addr.sin_port = htons(SERVER_PORT);

		 if ( bind(ecTestsock, (struct sockaddr *)&serv_addr, sizeof(sockaddr_in)) < 0) {
			 perror("Error calling bind");
		 }
	}

	int retal = listen(ecTestsock,8);
	if (retal <0) {
		perror("Error calling listen");
		*ret = -1;
	}
	int sock_len = sizeof(serv_addr);
	int client_sock = accept(ecTestsock, (struct sockaddr *)&serv_addr, (socklen_t*)&sock_len);
	if (client_sock < 0)
		*ret = -1;

}

int testComm_connect(){
	//Create Tasks
	rt_task_create(&test_task1, 0, 0 , 99, T_JOINABLE);
	rt_task_create(&test_task2, 0, 0 , 99, T_JOINABLE);

	int result1=1;
	int result2=1;

	//Run Tasks
	rt_task_start(&test_task1, &testComm_connect_t1, &result1);
	rt_task_start(&test_task2, &testComm_connect_t2, &result2);

	//Wait for all to finish and Join
	rt_task_join(&test_task1);
	rt_task_join(&test_task2);

	//Clean up Tasks
	rt_task_delete(&test_task1);
	rt_task_delete(&test_task2);

	return result1==result2;
}

void testComm_response_t1(void* arg){
	int * ret;
	ret = (int*) arg;
	Comm_Manager *testComm;
	testComm = new Comm_Manager(new Double_Buffer());
	testComm->readSocket();
	delete(testComm);
}

void testComm_response_t2(void* arg){
	int * ret;
	struct sockaddr_in serv_addr;

	ret = (int*) arg;
	if (ecTestsock == 0){
			ecTestsock = socket(AF_INET, SOCK_STREAM, 0);
		if (ecTestsock < 0) {
			*ret = -1;
		}
		serv_addr.sin_family = AF_INET;
		serv_addr.sin_addr.s_addr = htonl(INADDR_ANY);
		serv_addr.sin_port = htons(SERVER_PORT);

		 if ( bind(ecTestsock, (struct sockaddr *)&serv_addr, sizeof(sockaddr_in)) < 0) {
			 perror("Error calling bind");
		 }
	}

	int retal = listen(ecTestsock,8);
	if (retal <0) {
		perror("Error calling listen");
		*ret = -1;
	}
	int sock_len = sizeof(serv_addr);
	int client_sock = accept(ecTestsock, (struct sockaddr *)&serv_addr, (socklen_t*)&sock_len);
	if (client_sock < 0)
		*ret = -1;

	sreq_t servMsg;
	servMsg.type=STATUS_REQUEST;
	memset(&servMsg.cancel_hall_calls,0, MAX_FLOORS);
	memset(&servMsg.new_hall_calls,0, MAX_FLOORS);

	char buff[BUF_SIZE];
	memset(buff, 0, BUF_SIZE);
	memcpy(buff, (void*) &servMsg, sizeof(sreq_t));

	retal = write(ecTestsock, buff, BUF_SIZE);
	if (retal <0)
		*ret = -1;

	memset(buff, 0, BUF_SIZE);
	retal = read(ecTestsock, buff, BUF_SIZE);
}

int testComm_response(){
	//Create Tasks
	rt_task_create(&test_task1, 0, 0 , 99, T_JOINABLE);
	rt_task_create(&test_task2, 0, 0 , 99, T_JOINABLE);

	int result1=1;
	int result2=1;

	//Run Tasks
	rt_task_start(&test_task1, &testComm_connect_t1, &result1);
	rt_task_start(&test_task2, &testComm_connect_t2, &result2);

	//Wait for all to finish and Join
	rt_task_join(&test_task1);
	rt_task_join(&test_task2);

	//Clean up Tasks
	rt_task_delete(&test_task1);
	rt_task_delete(&test_task2);

	close (ecTestsock);

	return result1==result2;
}

int testFlrRun_getters(){
	FloorRun_Manager *fl;
	fl = new FloorRun_Manager();
	if (fl->get_cur_floor() != this_lift->getCur_floor())
		return -1;
	if (fl->get_dest() !=this_lift->getDest_floor())
		return -1;
	if (fl->get_status() != this_lift->getStatus())
		return -1;
	if (fl->get_dir() != this_lift->getDirection())
		return -1;
	if ((fl->check_reached_dest()))
			return -1;

	return 1; 		//PASSED
}

int testFlrRun_setters(){
	FloorRun_Manager *fl;
	fl = new FloorRun_Manager();

	fl->set_dest(MAX_FLOORS -1);
	fl->set_dir(DOWN);

	if (fl->get_dest() != MAX_FLOORS -1)
		return -1;

	if (fl->get_dir() != DOWN)
		return -1;

	return 1; 		//PASSED
}

int testFlrRun_connect(){
	FloorRun_Manager *fl;
	fl = new FloorRun_Manager();

	int t_sock = socket(AF_INET, SOCK_STREAM, 0);
	return fl->init_test_socket(t_sock);

}

int main(int argc, char* argv[]){

	mlockall(MCL_CURRENT | MCL_FUTURE);

	Tester * T_unit;
	T_unit = new Tester();

	//Register Tests Here

	//Setup Global var area for testing
	this_lift = new Elevator(0);

	//***** ELEVATOR TESTS *****
	T_unit->register_test(&testElevator_arrayClear,
			"Elevator", "Floor/Hall Call arrays reset");
	T_unit->register_test(&testElevator_arrayInit,
				"Elevator", "Floor/Hall Call arrays init");
	T_unit->register_test(&testElevator_setters,
				"Elevator", "Mutable Elevator Fields");
	T_unit->register_test(&testElevator_getters,
				"Elevator", "Shared Global varible area init");

	//reset Elevator Classes for other tests
	delete (this_lift);
	this_lift=new Elevator(0);

	//***** SUPERVISOR TESTS *****
	T_unit->register_test(testSupervisor_create, "Supervisor", "Initialization of Class");

	//***** Comm_Manager *****
	T_unit->register_test(&testComm_response, "Comm", "Msg Response test");
	T_unit->register_test(&testComm_connect, "Comm", "Startup connection test");

	//***** Double Buffer *****

	//***** Floor Run *****
	T_unit->register_test(testFlrRun_connect, "FlrManager", "Verify Test/Gui socket");
	T_unit->register_test(testFlrRun_setters, "FlrManager", "Verify Mutable state values");
	T_unit->register_test(testFlrRun_getters, "FlrManager", "Initialization of State Machine");

	T_unit->run_tests();

	delete(T_unit);
}
